#pragma once

#include <Windows.h>
#include <string>
#include <thread>
#include <mutex>
#include "../FilterSDK/ia.h"

typedef enum
{
	NoParity = 0,
	OddParity = 1,
	EvenParity = 2,
	MarkParity = 3,
	SpaceParity = 4
} EParity;

typedef enum
{
	OneStopBit,
	OnePointFiveStopBits,
	TwoStopBits
} EStopBits;

typedef enum
{
	NoFlowControl,
	CtsRtsFlowControl,
	CtsDtrFlowControl,
	DsrRtsFlowControl,
	DsrDtrFlowControl,
	XonXoffFlowControl
} EFlowControl;

typedef enum {
	IA_TAG_SERIAL_PORT_BAUDRATE,
	IA_TAG_SERIAL_PORT_PPARITY,
	IA_TAG_SERIAL_PORT_DATA_BITS,
	IA_TAG_SERIAL_PORT_STOP_BITS,
	IA_TAG_SERIAL_PORT_FLOW_CONTROL,
	IA_TAG_SERIAL_PPORT_RECEIVE_BY_LINE

} ESerialPortParams;

class ISerialPortReceiver
{
public:
	virtual int HandleData(const unsigned char* pBuffer, int bufferSize) = 0;
};

/**
 * @file SerialPort.h
 *
 * @brief	This class is used for serial port operations
 * @see		http://www.naughter.com/serialport.html
 *
 * @author cygia.com
 * Contact: lance.liao@cygia.com
 *
 */
class CSerialPort
{
public:
	CSerialPort();
	~CSerialPort();

	int Open(int  portNo, int  baudRate, EParity  parity, int  dataBits, EStopBits  stopsBits, EFlowControl flowControl);
	int Close() noexcept;
	int IsOpen() noexcept;
	int GetPortNo();

	int SetParam(ESerialPortParams paramName, int val) noexcept;
	int Flush() noexcept;

	int WriteBytes(unsigned char* pData, int len) noexcept;
	int WriteString(std::string text);

	int BytesWaiting(int* pLen);
	int ReadBytes(unsigned char* pBuffer, int bufferSize, int bytesToRead) noexcept;

	int SetSerialDataReceiver(ISerialPortReceiver* pSerialReceiver);

private:
	HANDLE  _hCom;
	int _portNum;

// For monitor thread only, you're not welcomed to access the variables and functions below
public:
	volatile int IsMonitorQuit;
	bool IsRecvByLine;

private:
	std::thread _receiveThread;
	std::mutex _serialSync;
	static void ReceiveWorker(CSerialPort* pSerialPort, ISerialPortReceiver* pSerialReceiver);

};

